package util;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ResourceBundle;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

import model.Preference;
import model.Settings;

/**
 * Static utility methods to create a Logger and to log messages to a Log file.
 * The format of the file name is as follows: <menuboxID>_yyyy_MM_dd.log.
 * The filename is changed every day soon after midnight.
 * 
 * @author richard
 */
public class LoggingUtils {

	//RBB
	private static final String USER_DIR = System.getProperty("user.dir");
	private static final String SEPARATOR = System.getProperty("file.separator");
	
	private static Logger logger = Logger.getLogger("com.mycompany");;
	private static long logFileTime;
	private static int menuBoxID = Preference.getInstance().getBoxID();
	private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy_MM_dd");
	private static final SimpleDateFormat timeStampFormatter = new SimpleDateFormat(
			"yyyy_MM_dd_HH:mm:ss:SSS");
	private static final LogFormatter logFormatter = new LogFormatter();
	private static FileHandler fileHandler;

	static {
		Level level = Level.SEVERE;
		try {
			ResourceBundle bundle = ResourceBundle.getBundle("Log");
			String levelStr = bundle.getString("Level").trim();
			level = (levelStr.equals("SEVERE")) ? Level.SEVERE
					: (levelStr.equals("WARNING")) ? Level.WARNING
					: (levelStr.equals("INFO")) ? Level.INFO
					: Level.SEVERE;	
		}
		catch (java.util.MissingResourceException mex) {
			System.out.println("Configuration Error: Cannot read Log.properties file in "
					+ LoggingUtils.class.getSimpleName() + ".static because file cannot be found/read."
					+ " The logging level has been set to the default value of SEVERE.");
        }		
		logger.setLevel(level);
		resetFileHandler();
	}

	public static void logStart(String classMethod) {
		//System.out.println(Preference.getInstance().isCheckLogging());
		if(Preference.getInstance().isCheckLogging())
		{
			logger.log(Level.WARNING, "Start of " + classMethod + ".");
		}
	}
	public static void logEnd(String classMethod) {
		if(Preference.getInstance().isCheckLogging())
		{
			logger.log(Level.WARNING, "End of " + classMethod + ".");
		}
	}

	public static void log(Level level, String message) {
		if(Preference.getInstance().isCheckLogging())
		{
			//System.out.println("Writting");
			logger.log(level, message + ".");
			
		}
	}
	
	public static void log(Level level, String message, Throwable throwable) {
		if(Preference.getInstance().isCheckLogging())
		{
			
			String stacktrace = "";
			if(throwable != null)
			{
				try
				{
					StringWriter sw = new StringWriter();
			        PrintWriter pw = new PrintWriter(sw, true);
			        throwable.printStackTrace(pw);
			        pw.flush();
			        sw.flush();
			        stacktrace = sw.toString();
				}
				catch(Exception e)
				{
					
				}
				
		        
			}
			
			try
			{
				message = ((message != null) ? message + "." : "") 
					+ ((throwable != null) ? "\n" + throwable.getClass().getSimpleName() 
						+ ": " + throwable.getMessage() + throwable.getCause().toString() : "");
			}
			catch(Exception e)
			{
				
			}
			
			logger.log(level, message+stacktrace, throwable);
			
			
		}
	}
	public static void log(Level level, String message, Thread thread) {
		if(Preference.getInstance().isCheckLogging())
		{
			try
			{
				message = "Thread Name=" + ((thread != null) ? thread.getName() : "null")
			    	+ ((message != null) ? message : "") + ".";
			}
			catch(Exception e)
			{}
			
			logger.log(level, message);
			
			thread.getName();
		}
	}
	
	public static void log(Level level, String message, Thread thread, Throwable throwable) {
		if(Preference.getInstance().isCheckLogging())
		{
			message = "Thread Name=" + ((thread != null) ? thread.getName() : "null")
			   	+ ((message != null) ? ((thread != null) ? "\n" : "") + message + "." : "") 
			   	+ ((throwable != null) ? ((thread != null || message != null) ? "\n" : "")
			   			+ throwable.getClass().getSimpleName() + ": " + throwable.getMessage() : "");
			logger.log(level, message);
			
			thread.getName();
		}
	}
	
	public static void logStart(String classMethod, Thread thread) {
		if(Preference.getInstance().isCheckLogging())
		{
			logger.log(Level.WARNING, "Start of Thread " + thread.getName() + " in " + classMethod + ".");
		}
	}
	public static void logEnd(String classMethod, Thread thread) {
		if(Preference.getInstance().isCheckLogging())
		{
			logger.log(Level.WARNING, "End of Thread " + thread.getName() + " in " + classMethod + ".");
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (logger.isLoggable(Level.ALL)) {
			System.out.println("ALL level is loggable");
		}
//		resetFileHandler();
		log(Level.SEVERE, "Hi y'all"); //', new NullPointerException("kaka is null."));
	}

	public static void incrementDateInLogName() {
		resetFileHandler();
	}	
	
	private static void resetFileHandler() {
		long nowTime = new Date().getTime();
		if (nowTime > logFileTime) {
			try {
				// Create an appending file handler
				FileHandler newHandler = new FileHandler(USER_DIR + SEPARATOR + Settings.LOG_DIRECTORY
						+ menuBoxID+"_"+dateFormatter.format(nowTime) + ".log", true);
				
				System.out.println(USER_DIR + SEPARATOR + Settings.LOG_DIRECTORY + String.valueOf(menuBoxID) + "_"
						+ dateFormatter.format(nowTime) + ".log");
				
				newHandler.setFormatter(logFormatter);
				logger.removeHandler(fileHandler);
				fileHandler = newHandler;
				logger.addHandler(fileHandler);
				File file = new File(Settings.LOG_DIRECTORY + menuBoxID + "_"
						+ dateFormatter.format(logFileTime) + ".log.lck");
				file.deleteOnExit();
				logFileTime = nowTime;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.println("System Error in " + LoggingUtils.class.getSimpleName()
						+ ".resetFileHandler(): Cannot reset a new FileHandler to the Logger of menuBoxID "
						+ menuBoxID + " due to following Exception.\nPlease cut and paste all console "
						+ "output and forward to Digital Menubox.");
				e.printStackTrace();
			}
		}
	}
}
